﻿using CsvHelper;
using Nop.Core.Domain.Catalog;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;

namespace SpotsHub.Tools.MassUploader
{
    public class ProductInfo
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string ShortDescription { get; set; }
        public string FullDescription { get; set; }
        public string SeName { get; set; }
        public int StoreId { get; set; }
        public decimal Price { get; set; }
        public decimal Weight { get; set; }
        public decimal Length { get; set; }
        public decimal Width { get; set; }
        public decimal Height { get; set; }
        public int OrderMaximumQuantity { get; set; }
        public int StockQuantity { get; set; }
        public string ProductCategory { get; set; }
        public string TaxCategory { get; set; }
    }
    public class ProductGenerator
    {
        #region Common

        private string _productsTemplatePath;

        private Dictionary<int, string> _productInfoLines = new Dictionary<int, string>();
        private DataTable _productInfo;
        private const char delimiter = ',';
        private const string infoHeader = "ID,Name,ShortDescription,FullDescription,SeName,StoreId,Price,Weight,Length,Width,Height,OrderMaximumQuantity,StockQuantity,ProductCategory,TaxCategory";
        private Dictionary<string, Type> _infoTypes;
        private const string rowFormat = "{0},,,,,{1},,,,,,,,,";
        private const int generateRows = 200;
        private const int maxPictures = 20;
        private const string pictureExt = "*.jpg";

        public const string ProductPicDir = "ProductPictures";
        public const string ProductInfoDir = "ProductInformation";
        public const string ProductInfoFilename = "ProductInfo.csv";
        public const string ProductPictureType = "image/jpeg";

        public DataTable ProductsInformation { get { return _productInfo; } }
        public Dictionary<int, List<string>> PictureFiles { get; private set; }

        private ProductGenerator(string productsTemplatePath)
        {
            _productsTemplatePath = productsTemplatePath;
            _infoTypes = new Dictionary<string, Type>();
            _infoTypes.Add("ID", typeof(int));
            _infoTypes.Add("Name", typeof(string));
            _infoTypes.Add("ShortDescription", typeof(string));
            _infoTypes.Add("FullDescription", typeof(string));
            _infoTypes.Add("SeName", typeof(string));
            _infoTypes.Add("StoreId", typeof(int));
            _infoTypes.Add("Price", typeof(decimal));
            _infoTypes.Add("Weight", typeof(decimal));
            _infoTypes.Add("Length", typeof(decimal));
            _infoTypes.Add("Width", typeof(decimal));
            _infoTypes.Add("Height", typeof(decimal));
            _infoTypes.Add("OrderMaximumQuantity", typeof(int));
            _infoTypes.Add("StockQuantity", typeof(int));
            _infoTypes.Add("ProductCategory", typeof(string));
            _infoTypes.Add("TaxCategory", typeof(string));
        }

        private string getPictureDir()
        {
            return Path.Combine(_productsTemplatePath, ProductPicDir);
        }

        private string getInfoDir()
        {
            return Path.Combine(_productsTemplatePath, ProductInfoDir);
        }

        private string getInfoFile()
        {
            return Path.Combine(_productsTemplatePath, ProductInfoDir, ProductInfoFilename);
        }

        public static ProductGenerator CreateProductsFromTemplate(string productsTemplatePath)
        {
            if (!Directory.Exists(productsTemplatePath))
            {
                throw new ArgumentException(String.Format("The folder doesn't exist: {0}", productsTemplatePath));
            }
            return new ProductGenerator(productsTemplatePath);
        }

        public void Import()
        {
            readProductInfo();
            getPicturePath();
        }

        #endregion

        private void readProductInfo()
        {
            _productInfo = new DataTable();
            var info = getInfoFile();

            if (!File.Exists(info))
            {
                throw new InvalidOperationException(String.Format("{0} doesn't exist."));
            }

            using (TextReader infoFile = new StreamReader(getInfoFile()))
            {
                string header = infoFile.ReadLine();
                if (header == null || !header.Equals(infoHeader, StringComparison.InvariantCulture))
                {
                    throw new InvalidDataException("The header of the information file is not expected.");
                }

                string[] cs = header.Split(delimiter);
                foreach (var c in cs)
                {
                    _productInfo.Columns.Add(c, _infoTypes[c]);
                }
            }

            using (var csv = new CsvReader(new StreamReader(info)))
            {
                while (csv.Read())
                {
                    if (csv.CurrentRecord.Length != _productInfo.Columns.Count ||
                        String.IsNullOrWhiteSpace(csv.CurrentRecord[1]))
                    {
                        break;
                    }

                    var r = _productInfo.NewRow();

                    for (int i = 0; i < _productInfo.Columns.Count; i++)
                    {
                        string name = _productInfo.Columns[i].ColumnName;

                        r.SetField(name, Convert.ChangeType(csv.GetField(name), _infoTypes[name]));
                    }

                    _productInfo.Rows.Add(r);
                }
            }

            //using (TextReader infoFile = new StreamReader(getInfoFile()))
            //{
            //    string header = infoFile.ReadLine();
            //    if (header == null || !header.Equals(infoHeader, StringComparison.InvariantCulture))
            //    {
            //        throw new InvalidDataException("The header of the information file is not expected.");
            //    }

            //    string[] cs = header.Split(delimiter);
            //    foreach (var c in cs)
            //    {
            //        _productInfo.Columns.Add(c, _infoTypes[c]);
            //    }

            //    string l = infoFile.ReadLine();
            //    string[] val = l.Split(delimiter);

            //    while (val.Length == cs.Length && !String.IsNullOrWhiteSpace(val[1]))
            //    {
            //        var r = _productInfo.NewRow();

            //        for (int i = 0; i < cs.Length; i++)
            //        {
            //            r.SetField(cs[i], Convert.ChangeType(val[i], _infoTypes[cs[i]]));
            //        }

            //        _productInfo.Rows.Add(r);

            //        l = infoFile.ReadLine();
            //        val = l.Split(delimiter);
            //    }
            //}
        }

        private void getPicturePath()
        {
            PictureFiles = new Dictionary<int, List<string>>();

            for (int id = 1; id <= generateRows; id++)
            {
                var p = new List<string>();
                string[] fs;
                for (int i = 1; i <= maxPictures; i++)
                {
                    var dir = Path.Combine(getPictureDir(), id.ToString(), i.ToString());
                    fs = Directory.GetFiles(dir, pictureExt);
                    if (fs.Length == 0)
                    {
                        continue;
                    }
                    if (fs.Length > 1)
                    {
                        throw new InvalidOperationException(String.Format("Found more than one picture: {0}", dir));
                    }

                    p.Add(fs[0]);
                }

                fs = Directory.GetFiles(Path.Combine(getPictureDir(), id.ToString()), pictureExt);
                p.AddRange(fs);

                if (p.Count > 0)
                {
                    PictureFiles.Add(id, p);
                }
            }
        }

        #region Template

        public static void CreateEmptyTemplate(string productsTemplatePath, int storeId)
        {

            if (!Directory.Exists(productsTemplatePath))
            {
                Directory.CreateDirectory(productsTemplatePath);
            }

            string picDir = Path.Combine(productsTemplatePath, ProductPicDir);
            string infoDir = Path.Combine(productsTemplatePath, ProductInfoDir);
            Directory.CreateDirectory(picDir);
            Directory.CreateDirectory(infoDir);

            for (int i = 1; i <= generateRows; i++)
            {
                Directory.CreateDirectory(Path.Combine(picDir, i.ToString()));
                for (int j = 1; j <= maxPictures; j++)
                {
                    Directory.CreateDirectory(Path.Combine(picDir, i.ToString(), j.ToString()));
                }
            }

            createProductInfoFile(Path.Combine(infoDir, ProductInfoFilename), storeId);
        }

        private static void createProductInfoFile(string filename, int storeId)
        {
            using (TextWriter tw = new StreamWriter(filename, false))
            {
                tw.WriteLine(infoHeader);
                for (int i = 1; i <= generateRows; i++)
                {
                    tw.WriteLine(String.Format(rowFormat, i, storeId));
                }
            }
        }

        #endregion
    }
}
